package io.github.qifan777.server.wallet.order.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.service.WxPayService;
import io.github.qifan777.server.Immutables;
import io.github.qifan777.server.dict.model.DictConstants;
import io.github.qifan777.server.payment.entity.Payment;
import io.github.qifan777.server.payment.entity.PaymentDraft;
import io.github.qifan777.server.payment.model.WeChatPayModel;
import io.github.qifan777.server.payment.service.WeChatPayService;
import io.github.qifan777.server.wallet.order.entity.WalletOrder;
import io.github.qifan777.server.wallet.order.entity.dto.WalletOrderInput;
import io.github.qifan777.server.wallet.order.repository.WalletOrderRepository;
import io.github.qifan777.server.wallet.pack.WalletPackage;
import io.github.qifan777.server.wallet.pack.repository.WalletPackageRepository;
import io.github.qifan777.server.wallet.root.service.WalletService;
import io.qifan.infrastructure.common.constants.ResultCode;
import io.qifan.infrastructure.common.exception.BusinessException;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;

@Service
@Slf4j
@AllArgsConstructor
@Transactional
public class WalletOrderService {
    private final WalletOrderRepository walletOrderRepository;
    private final WalletPackageRepository walletPackageRepository;
    private final WeChatPayService weChatPayService;
    private final WxPayService wxPayService;
    private final WalletService walletService;

    private Payment initPayment(BigDecimal price, String id) {
        return PaymentDraft.$.produce(draft -> {
            draft.setProductAmount(price)
                    .setPayType(DictConstants.PayType.WE_CHAT_PAY)
                    .setCouponAmount(BigDecimal.ZERO)
                    .setVipAmount(BigDecimal.ZERO)
                    .setDeliveryFee(BigDecimal.ZERO)
                    .setPayAmount(price)
                    .setId(id);
        });
    }

    public WxPayUnifiedOrderV3Result.JsapiResult save(WalletOrderInput walletOrderInput) {
        WalletPackage walletPackage = walletPackageRepository.findById(walletOrderInput.getWalletPackageId()).orElseThrow(() -> new BusinessException(ResultCode.NotFindError));
        String orderId = IdUtil.fastSimpleUUID();
        WalletOrder produce = Immutables.createWalletOrder(walletOrderInput.toEntity(), draft -> {
            draft.setId(orderId)
                    .applyBaseOrder(baseOrderDraft -> baseOrderDraft.setId(orderId)
                            .setPayment(initPayment(walletPackage.price(), orderId))
                            .setRemark("您已成功充值：" + walletPackage.name())
                            .setType(DictConstants.OrderType.RECHARGE_ORDER));
        });
        WalletOrder walletOrder = walletOrderRepository.save(produce);
        return weChatPayService.prepay(new WeChatPayModel().setBaseOrder(walletOrder.baseOrder())
                .setExpiredMinutes(5)
                .setNotifyUrl("/front/wallet-order/notify/pay/wechat"));

    }

    @SneakyThrows
    public String paymentNotifyWechat(String body, SignatureHeader signatureHeader) {
        WxPayNotifyV3Result.DecryptNotifyResult notifyResult = wxPayService.parseOrderNotifyV3Result(
                        body, signatureHeader)
                .getResult();
        log.info("收到微信支付回调通知，订单号：{}", notifyResult);
        String outTradeNo = notifyResult.getOutTradeNo();
        WalletOrder walletOrder = walletOrderRepository.findById(outTradeNo, WalletOrderRepository.COMPLEX_FETCHER_FOR_ADMIN).orElseThrow(() -> new BusinessException(ResultCode.NotFindError, "订单不存在"));
        StpUtil.switchTo(walletOrder.creator().id());
        walletService.change(Immutables.createWalletRecord(draft -> {
            draft.setType(DictConstants.WalletRecordType.RECHARGE)
                    .setWalletId(walletOrder.creator().id())
                    .setAmount(walletOrder.walletPackage().amount())
                    .setDescription("充值：" + walletOrder.walletPackage().name());
        }));
        // 更新支付信息
        return walletOrderRepository.save(Immutables.createWalletOrder(walletOrder, draft -> draft
                        .baseOrder()
                        .payment()
                        .setPayTime(LocalDateTime.now())
                        .setTradeNo(outTradeNo)))
                .id();

    }
}